package com.xique.park.service.biz.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xique.common.core.constant.HttpStatus;
import com.xique.common.core.utils.SecurityUtils;
import com.xique.common.core.utils.StringUtils;
import com.xique.common.core.web.domain.AjaxResult;
import com.xique.park.api.IParkPayCommandApi;
import com.xique.park.bean.domain.ParkChargeCarTemp;
import com.xique.park.bean.domain.ParkChargeRuleComm;
import com.xique.park.bean.dto.ChargeMngTypeGarageDto;
import com.xique.park.bean.request.web.chargeRule.*;
import com.xique.park.bean.search.web.ChargeMngTypeGarageSearch;
import com.xique.park.bean.transform.web.garageLaneDev.ChargeRuleTransform;
import com.xique.park.bean.vo.web.chargeRule.ChargeGarageVo;
import com.xique.park.bean.vo.web.chargeRule.ChargeRuleInfoVo;
import com.xique.park.bean.vo.web.chargeRule.ChargeRuleListVo;
import com.xique.park.bean.vo.web.chargeRule.MngTypeGarageVo;
import com.xique.park.service.biz.service.IParkChargeRuleBizService;
import com.xique.park.service.command.service.IParkChargeRuleCommandService;
import com.xique.park.service.service.IParkChargeCarTempService;
import com.xique.park.service.service.IParkChargeRuleCommService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 计费规则 biz Service
 *
 * @author xique
 */
@Service
public class ParkChargeRuleBizServiceImpl implements IParkChargeRuleBizService {

    @Autowired
    private IParkChargeRuleCommService chargeRuleCommService;

    @Autowired
    private IParkChargeCarTempService chargeCarTempService;

    @Autowired
    private IParkChargeRuleCommandService chargeRuleCommandService;

    @Autowired
    private IParkPayCommandApi parkPayCommandApi;

    @Override
    public AjaxResult getParkChargeRuleList() {
        ParkChargeRuleComm parkChargeRuleComm = new ParkChargeRuleComm();
        parkChargeRuleComm.setParkId(SecurityUtils.getParkId());
        List<ParkChargeRuleComm> list = chargeRuleCommService.selectParkChargeRuleCommList(parkChargeRuleComm);
        List<ChargeRuleListVo> vos = list.stream().map(item -> {
            ChargeRuleListVo vo = new ChargeRuleListVo();
            vo.setRuleName(item.getName());
            vo.setRuleId(item.getId());
            vo.setTemplate(String.valueOf(item.getTemplate()));
            return vo;
        }).collect(Collectors.toList());
        Map<String, Object> map = new HashMap<>(1);
        map.put("list", vos);
        return AjaxResult.success(map);
    }

    /**
     * 1、收费规则具体内容
     * 2、收费规则适用的管理类型和车库
     */
    @Override
    public AjaxResult getParkChargeRuleInfo(Long ruleId) {
        ChargeRuleInfoVo chargeRuleInfoVo = new ChargeRuleInfoVo();
        ParkChargeRuleComm ruleComm = chargeRuleCommService.selectParkChargeRuleCommById(ruleId);
        if (null == ruleComm) {
            return AjaxResult.error("未查询到记录");
        }
        chargeRuleInfoVo.setRuleId(ruleComm.getId());
        chargeRuleInfoVo.setRuleName(ruleComm.getName());
        chargeRuleInfoVo.setTemplate(null != ruleComm.getTemplate() ? String.valueOf(ruleComm.getTemplate()) : "");
        chargeRuleInfoVo.setCreateTime(ruleComm.getCreateTime());
        chargeRuleInfoVo.setUpdateTime(ruleComm.getUpdateTime());
        chargeRuleInfoVo.setContent(StringUtils.isNotEmpty(ruleComm.getContent()) ? JSON.parseObject(ruleComm.getContent()) : new JSONObject());
        // 管理类型和车库适用的计费规则处理
        ChargeMngTypeGarageSearch search = new ChargeMngTypeGarageSearch();
        search.setParkId(SecurityUtils.getParkId());
        List<ChargeMngTypeGarageDto> list = chargeCarTempService.selectChargeMngTypeGarageList(search);
        List<MngTypeGarageVo> vos = new ArrayList<>();
        Map<Long, List<ChargeMngTypeGarageDto>> mngTypeMap = new HashMap<>();
        // 返回给前端的已经绑定费率的管理类型和车库枚举列表，前端显示不用此列表
        List<TypeGarageObj> typeGarageObjList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(list)) {
            for (ChargeMngTypeGarageDto dto : list) {
                if (mngTypeMap.containsKey(dto.getMngTypeId())) {
                    List<ChargeMngTypeGarageDto> dtoList = mngTypeMap.get(dto.getMngTypeId());
                    dtoList.add(dto);
                    mngTypeMap.put(dto.getMngTypeId(), dtoList);
                } else {
                    List<ChargeMngTypeGarageDto> dtoList = new ArrayList<>(1);
                    dtoList.add(dto);
                    mngTypeMap.put(dto.getMngTypeId(), dtoList);
                }
                if (StringUtils.isNotNull(dto.getRuleId()) && ruleComm.getId().equals(dto.getRuleId())) {
                    TypeGarageObj obj = new TypeGarageObj();
                    obj.setMngTypeId(dto.getMngTypeId());
                    obj.setGarageId(dto.getGarageId());
                    obj.setSelected(true);
                    typeGarageObjList.add(obj);
                }
            }
        }
        for (Map.Entry<Long, List<ChargeMngTypeGarageDto>> entry : mngTypeMap.entrySet()) {
            MngTypeGarageVo vo = new MngTypeGarageVo();
            Long mngTypeId = entry.getKey();
            List<ChargeMngTypeGarageDto> dtoList = entry.getValue();
            String mngTypeName = dtoList.get(0).getMngTypeName();
            List<ChargeGarageVo> garageVos = new ArrayList<>(dtoList.size());
            for (ChargeMngTypeGarageDto dto : dtoList) {
                ChargeGarageVo garageVo = new ChargeGarageVo();
                garageVo.setGarageId(dto.getGarageId());
                garageVo.setGarageName(dto.getGarageName());
                garageVo.setSelected(StringUtils.isNotNull(dto.getRuleId()) && ruleComm.getId().equals(dto.getRuleId()));
                garageVos.add(garageVo);
            }
            vo.setMngTypeId(mngTypeId);
            vo.setMngTypeName(mngTypeName);
            vo.setGarageList(garageVos);
            vos.add(vo);
        }
        chargeRuleInfoVo.setTypeGarageList(vos);
        TypeGarage typeGarage = new TypeGarage();
        typeGarage.setList(typeGarageObjList);
        chargeRuleInfoVo.setTypeGarage(typeGarage);
        return AjaxResult.success(chargeRuleInfoVo);

    }

    @Override
    public AjaxResult getMngTypeGarageRule(MngTypeGarageRuleRequest request) {
        ParkChargeCarTemp chargeCarTemp = new ParkChargeCarTemp();
        chargeCarTemp.setParkId(SecurityUtils.getParkId());
        chargeCarTemp.setMngTypeId(request.getMngTypeId());
        chargeCarTemp.setGarageId(request.getGarageId());
        List<ParkChargeCarTemp> list = chargeCarTempService.selectParkChargeCarTempList(chargeCarTemp);
        Map<String, Object> map = new HashMap<>(2);
        if (CollectionUtils.isNotEmpty(list)) {
            map.put("hasRule", true);
            map.put("data", list);
        } else {
            map.put("hasRule", false);
        }
        return AjaxResult.success(map);
    }

    /**
     * 1、添加规则；
     * 2、收费规则适用的管理类型和车库；
     * 3、下发到设备；
     */
    @Override
    public AjaxResult addChargeRule(AddChargeRuleRequest request) {
        ParkChargeRuleComm ruleComm = ChargeRuleTransform.transformAddChargeRuleRequestToRuleComm(request);
        int count1 = chargeRuleCommService.insertParkChargeRuleComm(ruleComm);
        if (count1 <= 0) {
            return AjaxResult.error("收费规则保存失败");
        }

        // 下发收费规则
        List<ParkChargeRuleComm> ruleCommList = new ArrayList<>();
        ruleCommList.add(ruleComm);

        // 收费规则下发结果
        AjaxResult ruleRes = chargeRuleCommandService.downChargeRuleCommList(SecurityUtils.getParkId(), ruleCommList, "收费规则保存成功！");

        // 收费规则下发失败，直接返回
        if (ruleRes.get(AjaxResult.CODE_TAG).equals(HttpStatus.COMMAND_ERROR)) {
            return ruleRes;
        }

        // 管理类型和车库没有设置，直接返回保存成功，无需处理相关业务
        TypeGarage typeGarage = request.getTypeGarage();
        if (null == typeGarage || !typeGarage.isUpdate()) {
            return ruleRes;
        }
        List<TypeGarageObj> typeGarageObjList = typeGarage.getList();
        if (CollectionUtils.isEmpty(typeGarageObjList)) {
            return ruleRes;
        }

        // 处理管理类型和车库
        AjaxResult chargeRes = chargeTempHandle(ruleComm, typeGarageObjList);
        if (chargeRes.get(AjaxResult.CODE_TAG).equals(HttpStatus.SUCCESS)) {
            return AjaxResult.success("保存成功，收费规则下发成功，管理类型和车库下发成功");
        } else {
            return AjaxResult.error("收费规则下发成功，管理类型和车库下发失败，请重新下发");
        }
    }

    /**
     * 编辑收费规则
     */
    @Override
    public AjaxResult editChargeRule(EditChargeRuleRequest request) {
        ParkChargeRuleComm ruleComm = ChargeRuleTransform.transformEditChargeRuleRequestToRuleComm(request);
        int count1 = chargeRuleCommService.updateParkChargeRuleComm(ruleComm);
        if (count1 <= 0) {
            return AjaxResult.error("收费规则保存失败");
        }
        // 下发收费规则
        List<ParkChargeRuleComm> ruleCommList = new ArrayList<>();
        ruleCommList.add(ruleComm);

        // 收费规则下发结果
        AjaxResult ruleRes = chargeRuleCommandService.downChargeRuleCommList(SecurityUtils.getParkId(), ruleCommList, "保存成功！");

        // 收费规则下发失败，直接返回
        if (ruleRes.get(AjaxResult.CODE_TAG).equals(HttpStatus.COMMAND_ERROR)) {
            return ruleRes;
        }

        // 管理类型和车库没有设置，直接返回保存成功，无需处理相关业务
        TypeGarage typeGarage = request.getTypeGarage();
        if (null == typeGarage || !typeGarage.isUpdate()) {
            return ruleRes;
        }
        List<TypeGarageObj> typeGarageObjList = typeGarage.getList();
        if (CollectionUtils.isEmpty(typeGarageObjList)) {
            return ruleRes;
        }

        // 处理管理类型和车库
        AjaxResult chargeRes = chargeTempHandle(ruleComm, typeGarageObjList);
        if (chargeRes.get(AjaxResult.CODE_TAG).equals(HttpStatus.SUCCESS)) {
            return AjaxResult.success("保存成功，收费规则下发成功，管理类型和车库下发成功");
        } else {
            return AjaxResult.commandError("保存成功，收费规则下发成功，但管理类型和车库下发失败，请重新下发");
        }
    }

    @Override
    public AjaxResult chargeTempHandle(ParkChargeRuleComm ruleComm, List<TypeGarageObj> typeGarageObjList) {
        boolean commandResult = true;
        try {
            chargeCarTempService.batchDeleteByTypeGarage(typeGarageObjList);
            List<ParkChargeCarTemp> addChargeList = new ArrayList<>();
            List<ParkChargeCarTemp> removeChargeList = new ArrayList<>();
            for (TypeGarageObj obj : typeGarageObjList) {
                ParkChargeCarTemp chargeCarTemp = new ParkChargeCarTemp();
                chargeCarTemp.setParkId(SecurityUtils.getParkId());
                chargeCarTemp.setCarType(1L);
                chargeCarTemp.setUpdateUser(SecurityUtils.getUserId());
                chargeCarTemp.setMngTypeId(obj.getMngTypeId());
                chargeCarTemp.setGarageId(obj.getGarageId());
                chargeCarTemp.setChargeRuleId(ruleComm.getId());
                chargeCarTemp.setChargeRuleType(ruleComm.getTemplate().toString());
                if (obj.isSelected()) {
                    addChargeList.add(chargeCarTemp);
                } else {
                    removeChargeList.add(chargeCarTemp);
                }
            }
            if (CollectionUtils.isNotEmpty(removeChargeList)) {
                // 删除命令下发是否成功
                AjaxResult delChargeResult = chargeRuleCommandService.delChargeTempList(SecurityUtils.getParkId(), removeChargeList);
                if (delChargeResult.get(AjaxResult.CODE_TAG).equals(HttpStatus.COMMAND_ERROR)) {
                    commandResult = false;
                }
            }
            if (CollectionUtils.isEmpty(addChargeList)) {
                return AjaxResult.success("管理类型和车库处理成功");
            }
            int count = chargeCarTempService.batchInsert(addChargeList);
            if (count > 0) {
                // 下发至设备
                ParkChargeCarTemp search = new ParkChargeCarTemp();
                search.setChargeRuleId(ruleComm.getId());
                List<ParkChargeCarTemp> tempList = chargeCarTempService.selectParkChargeCarTempList(search);
                // 车辆管理类型是否下发成功
                AjaxResult downChargeResult = chargeRuleCommandService.downChargeTempList(SecurityUtils.getParkId(), tempList);
                if (downChargeResult.get(AjaxResult.CODE_TAG).equals(HttpStatus.COMMAND_ERROR)) {
                    commandResult = false;
                }
            } else {
                return AjaxResult.error("管理类型和车库保存失败");
            }
            if (commandResult) {
                return AjaxResult.success("管理类型和车库保存成功，管理类型和车库下发成功");
            } else {
                return AjaxResult.commandError("管理类型和车库保存成功，但管理类型和车库下发失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("管理类型和车库保存失败", e.getMessage());
        }
    }

    /**
     * 删除计费规则
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult delChargeRule(DeleteChargeRuleRequest request) {
        Long ruleId = request.getRuleId();
        // 给设备下发删除命令用
        List<ParkChargeRuleComm> ruleCommList = new ArrayList<>(1);
        ruleCommList.add(chargeRuleCommService.selectParkChargeRuleCommById(ruleId));
        chargeRuleCommService.deleteParkChargeRuleCommById(ruleId);
        ParkChargeCarTemp parkChargeCarTemp = new ParkChargeCarTemp();
        parkChargeCarTemp.setParkId(SecurityUtils.getParkId());
        parkChargeCarTemp.setChargeRuleId(ruleId);
        List<ParkChargeCarTemp> list = chargeCarTempService.selectParkChargeCarTempList(parkChargeCarTemp);
        if (CollectionUtils.isNotEmpty(list)) {
            List<TypeGarageObj> typeGarageObjList = list.stream().map(result -> {
                TypeGarageObj obj = new TypeGarageObj();
                obj.setMngTypeId(result.getMngTypeId());
                obj.setGarageId(result.getGarageId());
                return obj;
            }).collect(Collectors.toList());
            chargeCarTempService.batchDeleteByTypeGarage(typeGarageObjList);
        }

        AjaxResult delChargeRuleResult = chargeRuleCommandService.delChargeRuleCommList(SecurityUtils.getParkId(), ruleCommList);
        AjaxResult delChargeTempResult = chargeRuleCommandService.delChargeTempList(SecurityUtils.getParkId(), list);

        if (delChargeRuleResult.get(AjaxResult.CODE_TAG).equals(HttpStatus.COMMAND_ERROR)) {
            throw new IllegalArgumentException("下发删除收费规则命令失败，请重新删除");
        } else if (delChargeTempResult.get(AjaxResult.CODE_TAG).equals(HttpStatus.COMMAND_ERROR)) {
            throw new IllegalArgumentException("下发删除管理类型车库和收费规则对应关系失败，请重新删除");
        } else {
            return AjaxResult.success("删除成功");
        }
    }

    @Override
    public AjaxResult downAll() {
        Long parkId = SecurityUtils.getParkId();
        ParkChargeCarTemp temp = new ParkChargeCarTemp();
        temp.setParkId(parkId);
        List<ParkChargeCarTemp> parkChargeCarTempList = chargeCarTempService.selectParkChargeCarTempList(temp);
        ParkChargeRuleComm ruleComm = new ParkChargeRuleComm();
        ruleComm.setParkId(parkId);
        List<ParkChargeRuleComm> parkChargeRuleCommList = chargeRuleCommService.selectParkChargeRuleCommList(ruleComm);
        try {
            AjaxResult downChargeTempResult = null;
            AjaxResult downChargeRuleCommResult = null;
            if (CollectionUtils.isNotEmpty(parkChargeCarTempList)) {
                downChargeTempResult = chargeRuleCommandService.downChargeTempList(parkId, parkChargeCarTempList);
            }
            if (CollectionUtils.isNotEmpty(parkChargeRuleCommList)) {
                downChargeRuleCommResult = chargeRuleCommandService.downChargeRuleCommList(parkId, parkChargeRuleCommList, "");
            }
            if (null != downChargeTempResult && downChargeTempResult.get(AjaxResult.CODE_TAG).equals(HttpStatus.COMMAND_ERROR)) {
                return AjaxResult.commandError("下发管理类型车库和收费规则对应关系失败");
            }
            if (null != downChargeRuleCommResult && downChargeRuleCommResult.get(AjaxResult.CODE_TAG).equals(HttpStatus.COMMAND_ERROR)) {
                return AjaxResult.commandError("下发收费规则失败");
            }
            return AjaxResult.success("下发成功");
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.commandError("下发失败", e.getMessage());
        }
    }

    @Override
    public AjaxResult feeTest(FeeTestRequest request) {
        // 解析请求参数
        Map<String, Object> map = new HashMap<>(6);
        Integer ruleId = request.getRuleId();
        // 获取参数中的redId，查询price
        ParkChargeRuleComm parkChargeRuleComm = chargeRuleCommService.selectParkChargeRuleCommById(ruleId.longValue());
        String price = parkChargeRuleComm.getContent();
        if (StringUtils.isEmpty(price)) {
            return AjaxResult.error("请求失败,收费规则内容不能为空");
        }
        if (7 != parkChargeRuleComm.getTemplate()) {
            map.put("library", "common");
        } else {
            map.put("library", "custom_" + parkChargeRuleComm.getRemark());
        }
        map.put("id", ruleId);
        map.put("rec_id", ruleId);
        map.put("price", price);
        map.put("inTime", request.getInTime());
        map.put("outTime", request.getOutTime());
        map.put("template", request.getTemplate());
        try {
            Object result = parkPayCommandApi.feeTest(map);
            Map<String, Object> data = new HashMap<>(1);
            data.put("result", result);
            data.put("unit", "分");
            return AjaxResult.success("请求成功", data);
        } catch (Exception e) {
            return AjaxResult.error("请求失败", e.getMessage());
        }
    }

    @Override
    public AjaxResult getMngTypeGarage() {
        // 管理类型和车库适用的计费规则处理
        ChargeMngTypeGarageSearch search = new ChargeMngTypeGarageSearch();
        search.setParkId(SecurityUtils.getParkId());
        List<ChargeMngTypeGarageDto> list = chargeCarTempService.selectChargeMngTypeGarageList(search);
        Map<Long, List<ChargeMngTypeGarageDto>> mngTypeMap = new HashMap<>(16);
        if (CollectionUtils.isNotEmpty(list)) {
            for (ChargeMngTypeGarageDto dto : list) {
                if (mngTypeMap.containsKey(dto.getMngTypeId())) {
                    List<ChargeMngTypeGarageDto> dtoList = mngTypeMap.get(dto.getMngTypeId());
                    dtoList.add(dto);
                    mngTypeMap.put(dto.getMngTypeId(), dtoList);
                } else {
                    List<ChargeMngTypeGarageDto> dtoList = new ArrayList<>(1);
                    dtoList.add(dto);
                    mngTypeMap.put(dto.getMngTypeId(), dtoList);
                }
            }
        }
        List<MngTypeGarageVo> vos = new ArrayList<>();
        for (Map.Entry<Long, List<ChargeMngTypeGarageDto>> entry : mngTypeMap.entrySet()) {
            MngTypeGarageVo vo = new MngTypeGarageVo();
            Long mngTypeId = entry.getKey();
            List<ChargeMngTypeGarageDto> dtoList = entry.getValue();
            String mngTypeName = dtoList.get(0).getMngTypeName();
            List<ChargeGarageVo> garageVos = new ArrayList<>(dtoList.size());
            for (ChargeMngTypeGarageDto dto : dtoList) {
                ChargeGarageVo garageVo = new ChargeGarageVo();
                garageVo.setGarageId(dto.getGarageId());
                garageVo.setGarageName(dto.getGarageName());
                garageVo.setSelected(false);
                garageVos.add(garageVo);
            }
            vo.setMngTypeId(mngTypeId);
            vo.setMngTypeName(mngTypeName);
            vo.setGarageList(garageVos);
            vos.add(vo);
        }
        ChargeRuleInfoVo chargeRuleInfoVo = new ChargeRuleInfoVo();
        chargeRuleInfoVo.setTypeGarageList(vos);
        return AjaxResult.success(chargeRuleInfoVo);
    }

}
